package jwater.org.springframework.boot.loader;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import jwater.org.springframework.boot.loader.archive.Archive;
import jwater.org.springframework.boot.loader.archive.Archive.Entry;
import jwater.org.springframework.boot.loader.archive.Archive.EntryFilter;
import jwater.org.springframework.boot.loader.archive.JarFileArchive;
import jwater.org.springframework.boot.loader.jar.JarFile;
import jwater.org.springframework.core.io.Resource;
import jwater.org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import jwater.org.springframework.core.io.support.ResourcePatternResolver;

/**
 * @description:
 * @author: jnner
 * @createDate: 2021/2/5
 * @version: 1.0
 */
public class JWaterSpringbootLauncher extends Launcher {
    static final String BOOT_INF_CLASSES = "BOOT-INF/classes/";
    static final String BOOT_INF_LIB = "BOOT-INF/lib/";
    protected String mainClass;

    public JWaterSpringbootLauncher(String mainClass) {
        this.mainClass = mainClass;
    }

    @Override
    protected String getMainClass() throws Exception {
        return mainClass;
    }

    private Resource[] getResources(String locationPattern) throws IOException {
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        Resource resources[] = resolver.getResources(locationPattern);
        if (resources != null) {
            return resources;
        }
        return new Resource[0];
    }

    @Override
    protected List<Archive> getClassPathArchives() throws Exception {
        List<Archive> archives = new ArrayList<Archive>();
        Set<String> list = new HashSet<String>();
        Resource[] resources = getResources("classpath*:/BOOT-INF/lib/*.jar");
        if (resources != null) {
            for (Resource resource : resources) {
                String filePath = resource.getURL().getFile();
                int index = filePath.indexOf("!");
                if (index > -1) {
                    filePath = filePath.substring(5, index);
                    list.add(filePath);
                }
            }
        }
        for (String filePath : list) {
            JarFileArchive jarFileArchive = new JarFileArchive(new File(filePath));
            List<Archive> jarFileArchives = jarFileArchive.getNestedArchives(new EntryFilter() {
                @Override
                public boolean matches(Entry entry) {
                    return isNestedArchive(entry);
                }
            });
            archives.addAll(jarFileArchives);
        }
        return archives;
    }

    protected boolean isNestedArchive(Archive.Entry entry) {
        if (entry.isDirectory()) {
            return entry.getName().equals(BOOT_INF_CLASSES);
        }
        return entry.getName().startsWith(BOOT_INF_LIB);
    }

    public void launch(String[] args) throws Exception {
        JarFile.registerUrlProtocolHandler();
        ClassLoader classLoader = createClassLoader(getClassPathArchives());
        launch(args, getMainClass(), classLoader);
    }
}
